﻿#region copyright info
//------------------------------------------------------------------------------
// <copyright company="ChaosStudio">
//     Copyright (c) 2002-2010 巧思工作室.  All rights reserved.
//     Contact:		MSN:zhouyu@cszi.com , QQ:478779122
//		Link:				http://www.69sea.com http://www.cszi.com
// </copyright>
//------------------------------------------------------------------------------
#endregion
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Timers;
using log4net;
using Timer=System.Timers.Timer;

namespace CS.WinService
{
    /// <summary>
    ///   任务管理器
    ///   专为WindowsService服务
    ///   Task 计划的伤务 Ver:0.3.1
    /// </summary>
    /// 
    /// <description class = "CS.WinService.Task4WinService">
    ///   
    /// </description>
    /// 
    /// <history>
    ///   2010-3-1 14:55:12 , zhouyu ,  创建
    ///   2010-7-7 14:32  , zhouyu , 加上配置初始化 行230
    ///  </history>
    public sealed class Task4WinService:IDisposable
    {

        #region 相关属性设定
        /// <summary>
        /// 程序运行日志 
        /// </summary>
        private static readonly ILog logRun = LogManager.GetLogger(typeof(Task4WinService));

        /// <summary>
        /// 所有任务驱动集合
        /// </summary>
        private static  IList<TaskProvider> _taskProviders;
      
        /// <summary>
        /// 监视工人(轮询工作计时器)
        /// </summary>
        Timer _watchWorker;

        /// <summary>
        /// 配置
        /// </summary>
        private TaskConfig _config;


        #endregion


        #region 单例实现
        
        ///// <summary>
        ///// 默认构造
        ///// </summary>
        //public Task4WinService()
        //{
        //    //Status = () => ServiceStatusType.Stoped;
        //}


        #endregion


        #region 工作回调

        /// <summary>
        /// 监视轮询工作
        /// 发现有可执行的任务时，启动该任务所在的驱动以使其执行。
        /// Note:Working时就要每次重读配置，释放后的任务再也回不来了。
        /// </summary>
        public void Working(object sender,ElapsedEventArgs args)
        {
            //Note:线程锁定
            lock (this)
            {
                _watchWorker.Stop();

                logRun.DebugFormat("↓---- 任务监视轮询开始 ----");
                logRun.DebugFormat("上次轮询延时: {0}ms ，有[{1}]个任务。", _watchWorker.Interval, _taskProviders.Count);

                //Note:可能重新载入所有配置，
                //Todo:重新载入前可能要停止所有任务。
                if (_config == null)
                {
                    logRun.WarnFormat("配置实例为null，系统尝试修复服务[重启开始...]");
                    Stop(); //先停止全部 再重启动全部
                    Start();
                    if(_config==null)
                        throw new  OperationCanceledException("config, 配置对象为空，监视工人取消工作。");
                }

                foreach (var provider in _taskProviders)
                {
                    var now = SystemTime.Now();
                    var launchTime = provider.Task.CalculateLaunchTime();

                    //Note:lanuchTime有效的任务不能移出，移出了再如何启动呢？
                    //Note:lanuchTime小于当前时间的要启动，这种任务可能是需要补全的。

                    //下次启动时间为null，移出再也不会启动的任务
                    if (launchTime == null)
                    {
                        provider.Dispose(); //任务已停止，直接释放资源
                        _taskProviders.Remove(provider);
                        logRun.DebugFormat("○任务[{0}:{1}]下次启动时间为null ，移出队列，还余{2}个任务。", provider.Task.Job.Id,
                                           provider.Task.Job.Name, _taskProviders.Count);
                        continue;
                    }

                    if (now.Add(_config.WatchTimer.WorkingInterval).AddMilliseconds(_config.WatchTimer.DelayMillisecond) <
                        launchTime  && provider.Task.WorkSetting.Interval.Times > 0)
                    {
                        logRun.DebugFormat("○任务[{0}:{1}需运行:{2}]下次启动时间[{3:u}]。", provider.Task.Job.Id, provider.Task.WorkSetting.Interval.Times, provider.Task.Job.Name, launchTime);
                        continue;
                    }

                    //正在运行时，任务不可再次运行
                    if (TaskStatusType.Runing == (provider.Task.Job.Execution.Status & TaskStatusType.Runing))
                    {
                        logRun.DebugFormat("任务[{0}:{1}]正在运行中。", provider.Task.Job.Id, provider.Task.Job.Name);
                        continue;
                    }
                    
                    //启动任务
                    //provider.Resources = _config.Resources;    //公有资源引用
                    provider.Start();
                    logRun.DebugFormat("任务[{0}:{1}]于{2:MM-dd HH:mm:ss,fff}进行启动尝试。", provider.Task.Job.Id,
                                       provider.Task.Job.Name, now);
                }

                //第一次运行时更改监工的下次轮询时间
                if (_config.WatchTimer.WorkingInterval.Times == 0)
                {
                    var t = (TimeSpan) _config.WatchTimer.WorkingInterval;
                    _watchWorker.Interval = t.TotalMilliseconds;
                    _config.WatchTimer.WorkingInterval.Times++;
                }


                logRun.DebugFormat("↑---- 任务监视轮询结束 ----");
                _watchWorker.Start();
            }
        }


        #endregion


        #region 监督配置事件 tasks.config

        /// <summary>
        /// 发生配置变化后约30秒延迟时间才会全部重启完成。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void TaskConfigChanged(object sender,FileSystemEventArgs e)
        {
            try
            {
                //Note:线程锁定
                lock (this)
                {
                    logRun.DebugFormat("文件{0}发生变化。变化类型:{1}", e.Name, e.ChangeType);
                    _watchWorker.Stop();
                    _config = null;
                    Stop(); //Todo:停止所有任务,这儿是不是加上任务停止完成的回调通知呢？
                    Thread.Sleep(2000);    //给一些时间来让任务尽可能的停止。
                    Start();
                }
            }
            catch (Exception ex)
            {
                logRun.Debug("重载任务配置发生异常",ex);
                throw;
            }
        }

        #endregion


        #region 实例化一个任务 InitTaskProvider

        /// <summary>
        /// 初始化一个任务的驱动实例
        /// </summary>
        ///// <param name="config">原始配置</param>
        /// <param name="taskInfo">任务配置信息</param>
        TaskProvider InitTaskProvider(TaskInfo taskInfo)
        {
            logRun.DebugFormat("任务[{0}:{1}]开始初始化...", taskInfo.Job.Id, taskInfo.Job.Name);

            var nextRun = taskInfo.CalculateLaunchTime();
            if (nextRun == null)
            {
                logRun.DebugFormat("任务[{0}:{1}]下次运行时间为null，取消实例化。", taskInfo.Job.Id, taskInfo.Job.Name);
                return null;
            }

            //var sb = new StringBuilder();
            //实例化驱动实现
            try
            {
                var typeInfo = taskInfo.Type.Split(',');
                var assembly = Assembly.Load(typeInfo[1].Trim());        //如果错误，这儿会引发异常，下面就不用执行了
                var type = assembly.GetType(typeInfo[0].Trim());
                if (type == null || !typeof(TaskProvider).IsAssignableFrom(type))
                {
                    var msg = string.Format("配置:任务[{0}:{1}]的type属性[{2}]无效，请使用实现了TaskProvider的类，服务中止。", taskInfo.Job.Id, taskInfo.Job.Name, taskInfo.Type);
                    //log.Error(sb);
                    throw new ConfigurationErrorsException(msg);
                }
                var task = assembly.CreateInstance(typeInfo[0]) as TaskProvider;
                if (task != null)
                {
                    task.Task = taskInfo;
                    task.Resources = _config.Resources;    //公有资源引用
                    task.LoadExtendConfig();   //由于非new方式创建实现，无法在构造中获得配置
                    //task.ServiceStatus = Status();
                    logRun.DebugFormat("任务[{0}:{1}]实例化成功。", taskInfo.Job.Id, taskInfo.Job.Name);
                    
                }
                else
                {
                    logRun.DebugFormat("任务[{0}:{1}]实例化为null。", taskInfo.Job.Id, taskInfo.Job.Name);
                }

                return task;
            }
            catch (Exception ex)
            {
                var msg = string.Format("配置:任务[{0}:{1}]的type属性[{2}]无效，实例化异常，服务中止。", taskInfo.Job.Id, taskInfo.Job.Name, taskInfo.Type);
                logRun.Fatal(msg, ex);
                throw new ConfigurationErrorsException(msg);
            }
        }

        #endregion


        #region 监工工作开始与暂停

        /// <summary>
        /// 开始执行全部。
        /// </summary>
        public void Start()
        {
            //Note:线程锁定
            lock (this)
            {
                logRun.DebugFormat("----- 服务启动开始 -----");

                //Note:载入所有配置
                _config = TaskConfig.GetInstance();
                //config.Changed -= TaskConfigChanged;
                _config.Changed += TaskConfigChanged; //只保留一次的事件
                _config.WatchTimer.WorkingInterval.Times = 0;

                //Note:初始化计时器
                _watchWorker = new Timer(_config.WatchTimer.DelayMillisecond);    //Note:第一次运行不按间隔时间执行。
                _watchWorker.Elapsed += Working;
                logRun.DebugFormat("监视工人第一次工作将于{0:0.00}秒后执行", _config.WatchTimer.DelayMillisecond / 1000.00);

                //Note:初始化任务集合
                _taskProviders = new List<TaskProvider>();

                //循环实例化
                foreach (var task in _config.Tasks)
                {
                    var provider = InitTaskProvider(task);
                    if (provider == null) continue;
                    _taskProviders.Add(provider);
                    provider.ExecutionConfig = _config.Execution;
                    
                }

                _watchWorker.Start();   //启动工作回调
                //Status = () => ServiceStatusType.Runing;
                logRun.DebugFormat("----- 服务启动完成 -----");
            }
        }

        /// <summary>
        /// 开始停止全部。
        /// 并清空集合
        /// </summary>
        public void Stop()
        {
            //Note:线程锁定
            lock (this)
            {
                if(_watchWorker == null) return;
                logRun.DebugFormat("----- 服务停止开始 -----");
                _watchWorker.Stop();
                if (_taskProviders.Count > 0)
                {
                    //开始通知所有任务，让其终止。
                    foreach (var task in _taskProviders)
                    {
                        if (task == null) continue;
                        task.Stop();
                    }
                    _taskProviders = null;
                }
                //所有任务停止后 释放监工计时器
                _watchWorker.Dispose();
                _watchWorker = null;    //干掉引用
                //Status = () => ServiceStatusType.Stoped;
                logRun.DebugFormat("----- 服务停止完成 -----");
            }
        }
        
        /// <summary>
        /// 暂停所有任务。
        /// </summary>
        public void Pause()
        {
            //Note:线程锁定
            lock (this)
            {
                logRun.DebugFormat("----- 服务暂停开始 -----");
                _watchWorker.Stop();
                foreach (var task in _taskProviders)
                {
                    task.Pause();
                }
                //Status = () => ServiceStatusType.Suspend;
                logRun.DebugFormat("----- 服务暂停结束 -----");
            }
        }

        /// <summary>
        /// 从暂停处重新执行。
        /// </summary>
        public void Resume()
        {
            //Note:线程锁定
            lock (this)
            {
                logRun.DebugFormat("----- 服务恢复开始 -----");
                foreach (var task in _taskProviders)
                {
                    task.Resume();
                }
                _watchWorker.Start();
                //Status =() => ServiceStatusType.Runing;
                logRun.DebugFormat("----- 服务恢复结束 -----");
            }
        }

        #endregion


        /// <summary>
        /// 资源释放
        /// </summary>
        public void Dispose()
        {
            logRun.DebugFormat("----- 服务资源释放开始 -----");
            

            logRun.DebugFormat("----- 服务资源释放结束 -----");
        }

        ///// <summary>
        ///// 宿主服务状态
        ///// </summary>
        //public static Func<ServiceStatusType> Status;   //返回时间的一个委托
       
    }


    
    

    /// <summary>
    /// 任务服务状态
    /// </summary>
    public enum ServiceStatusType
    {
        /// <summary>
        /// 未知
        /// </summary>
        Unknow = 0,

        /// <summary>
        /// 已停止
        /// </summary>
        Stoped = 1,

        /// <summary>
        /// 运行中
        /// </summary>
        Runing = 2,

        /// <summary>
        /// 暂停中
        /// </summary>
        Suspend = 3,

    }

   
}